/*
 * mythread.h -- interface of user threads library
 */

#ifndef MYTHREAD_H
#define MYTHREAD_H

#ifndef FALSE
#define FALSE 0
#endif

#ifndef TRUE
#define TRUE 1
#endif

#include <ucontext.h>
#include "myqueue.h"

typedef struct mythread_attr {    /* thread attributes */
	int stacksize;                  /* minimum stack size in bytes */
	int detachstate;                /* detachable/joinable (TRUE/FALSE) */
	void* stackaddr;		/* base address of stack */
} mythread_attr_t;

typedef struct mythread {         /* thread control block */
	int state;                      /* state of execution */
	void * (*start_func)(void*);    /* thread_func to be called */
	void *arg;                      /* thread_arg arguments of thread_func */
	mythread_queue_t joinq;         /* Q of threads waiting for my return */
	ucontext_t context;             /* save area for context switches */
	void *returnValue;              /* Pointer to the detached function's return value */
	mythread_attr_t attr;           /* attributes */		
} *mythread_t;

/*
 * mythread_block - remove currently running thread off run q,
 * if q is non-NULL, enq this thread on q, suspend the thread,
 * add the state flags to the thread's state (via bit-wise OR | state)
 * and activate ready threads if an LWP becomes available
 * pre: must be in monolithic kernel
 * post: return outside the monolithic kernel
 */
void mythread_block(mythread_queue_t *q, int state);

/*
 * mythread_unblock - resumes the thread at the head of q,
 * remove the state flags to the thread's state (via bit-wise AND & ~state)
 * and activate the thread if an LWP becomes available (o/w mark as ready)
 * pre: must be in monolithic kernel
 * post: return outside the monolithic kernel
 */
void mythread_unblock(mythread_queue_t *q, int state);

/*
 * mythread_create - prepares context of new_thread_ID as start_func(arg),
 * attr is an attribute object specifying thread behavior if default behavior 
 * is not desired. Threads are activated (run) according to the number of available 
 * LWPs or are marked as ready.
 */
int mythread_create(mythread_t *new_thread_ID,
					mythread_attr_t *attr,
					void * (*start_func)(void *),
					void *arg);

/*
 * mythread_yield - switch from running thread to the next ready one
 */
int mythread_yield(void);

/*
 * mythread_self - thread id of running thread
 */
mythread_t mythread_self(void);

/*
 * mythread_join - suspend calling thread if target_thread has not finished,
 * enqueue on the join Q of the target thread, then dispatch ready thread;
 * once target_thread finishes, it activates the calling thread / marks it
 * as ready.
 */
int mythread_join(mythread_t target_thread, void **status);

/*
 * mythread_exit - exit thread, awakes joiners on return
 * from thread_func and dequeue itself from run Q before dispatching run->next
 */
void mythread_exit(void *retval);

/*
 * mythread_detach - make target_thread unable to be joined with mythread_join(). 
 * target_thread will be freed immediately upon termination rather than waiting to 
 * be joined by another thread.
 */
int mythread_detach(mythread_t target_thread);

/*
 * mythread_attr_init - initialize attribute object, *tattr, to default 
 * attribute values.
 */
int mythread_attr_init(mythread_attr_t *tattr);

/*
 * mythread_attr_destroy - remove resources allocated for *tattr during 
 * initialization.
 */
int mythread_attr_destroy(mythread_attr_t *tattr);

/*
 * mythread_attr_getdetachstate - return (in *detachstate)  the thread create state, 
 * that is the detachstate attribute of *tattr, which is either detached or joinable.
 */
int mythread_attr_getdetachstate(const mythread_attr_t *tattr, int *detachstate);

/*
 * mythread_attr_setdetachstate - set the detachstate attribute in *tattr to the state
 * specified by detachstate param (detached or joinable).
 */
int mythread_attr_setdetachstate(mythread_attr_t *tattr, int detachstate);

/*
 * mythread_attr_getstackaddr - return the base address for the thread's stack,
 * that is, the *stackaddr attribute of *tattr.
 */
int mythread_attr_getstackaddr(mythread_attr_t *tattr, void **stackaddr);

/*
 * mythread_attr_setstackaddr - set the base address of the stack of the thread that
 * is to be created.
 */
int mythread_attr_setstackaddr(mythread_attr_t *tattr, void *stackaddr);

/*
 * mythread_attr_getstacksize - return (in *size) the thread creation stack size defined
 * in *tattr. 
 */
int mythread_attr_getstacksize(mythread_attr_t *tattr, int *stacksize);

/*
 * mythread_attr_setstacksize - define the thread creation stack size attribute in 
 * tattr. stacksize should not be less than the system-defined minimum stack size.
 */
int mythread_attr_setstacksize(mythread_attr_t *tattr, int stacksize);


#endif /* MYTHREAD_H */
